package com.cskaoyan.javase._1extends._7initialization._1basic;

/**
 * 引例:
 * 创建一个Person类，有name属性和eat方法。
 * 创建一个Star类，有stageName属性和sing方法。
 * Star类要继承Person类。
 * 创建Star这个子类对象，通过画图/运行代码等研究子类对象初始化的过程。
 *
 * 研究一下子类对象的初始化流程:
 * 至少需要考虑以下问题：
 *      1.类加载，创建子类对象，会类加载父类吗？顺序是什么？
 *          肯定是需要类加载父类的,而且顺序应该是"先父后子"
 *          实际上,触发子类的类加载,会优先类加载父类,是类加载的时机之一.
 *
 *      2.类加载结束后，创建子类对象，会连带创建父类对象吗？
 *          不是的,只创建了一个子类对象,没有创建父类对象
 *
 *      3.明确只会创建一个子类对象后还需要注意的是：
 *          子类对象是要划分区域来存储不同内容的。
 *          a.子类对象中会专门开辟一片独立的区域，用来存储父类的成员变量
 *          b.而子类自身的成员仍会存储在自身对象当中。
 *          这样子类对象就被划分为了两个区域：
 *              自身成员的区域，自身对象的区域，该区域用隐含this引用指向。
 *              父类成员的区域，该区域用super关键字指向。
 *          this指向当前子类对象,super指向子类对象中的父类成员区域
 *          所以this是包含super的,this的范围更大,它直接表示当前子类对象
 *
 *
 *      4.子类对象中会同时存储父子类成员变量,那么它们赋值是如何进行的呢?
 *      首先，在众多给成员变量的赋值手段中，我们先排除默认初始化
 *      具有默认值的过程永远是最先进行的，我们无需考虑它们谁先谁后
 *      只需要知道——所有其它赋值都是在默认值基础上进行的。
 *      排除默认初始化后，还剩下的创建对象过程中的赋值手段有：
 *          a.显式赋值
 *          b.构造代码块赋值
 *          c.构造器赋值
 *      父子类的成员变量的赋值,是先父后子还是先子后父呢?
 *      肯定是"先父后子"的
 *
 *      5.(重点)父子类成员变量的赋值顺序的"先父后子"，是怎么保证的呢？为什么能够体现出这种特点呢？
 *      猜测:
 *      只需要保证父类构造器的执行,先于子类构造器执行就能够保证"先父后子"了.
 *      在创建子类对象时,父类的构造器会执行,而且是会先于子类构造器执行.
 *      通过验证,以上猜想是合理的,正确的
 *
 *      父类的构造器先于子类的构造器而执行,那么这个结果是如何保证的呢?
 *      两种子类对象的初始化方式:
 *      a.隐式的子类对象初始化
 *      重要结论：
 *      在任何一个Java类的任何一个构造器当中，如果第一行没有明确的去调用别的构造器
 *      （通过this或super关键字）
 *      那么它的第一行一定隐含一条语句：
 *      super();
 *      该行语句表示去调用父类的无参构造方法。
 *      通过隐含super()的方式,保证父类构造器先于子类执行,这种子类对象的初始化方式,称之为"隐式的子类对象初始化"
 *      b.如果需要给父类成员变量赋值,那么就需要明确调用父类的有参构造,称之为"子类对象的显式初始化"
 *      语法:
 *      在子类构造器的第一行使用
 *      super(实参)
 *      来表示调用父类的有参构造器
 *
 *
 * @since 15:56
 * @author wuguidong@cskaoyan.onaliyun.com
 */
public class Demo {
    public static void main(String[] args) {
        Star s = new Star();
        // System.out.println(s.stageName);

        Star s2 = new Star("李四");
        System.out.println(s2.name);
        System.out.println(s2.stageName);
    }
}

class Person {
    // static {
    //     System.out.println("Person类加载了!");
    // }
    String name = "张三";
    {
        System.out.println("Person父类的构造代码块");
    }

    public void eat() {
        System.out.println("民以食为天!");
    }

    public Person() {
    }

    public Person(String name) {
        this.name = name;
    }
}

class Star extends Person {
    // static {
    //     System.out.println("Star类加载了!");
    // }
    String stageName = name + "-法外狂徒";
    {
        System.out.println("Star子类的构造代码块");
    }

    public void sing() {
        System.out.println("唱跳rap篮球!");
    }

    public Star() {
        // super();
    }

    // 显式子类对象初始化
    public Star(String name){
        super(name);
    }
}